﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Windows.Media.Imaging;
using System.IO;
using SomethingSpacialClassLib.Web;
using SomethingSpacial.AppServices;
using System.Collections.ObjectModel;
using System.Windows.Threading;
using System.ServiceModel.DomainServices.Client;

namespace SomethingSpacialSpeakerNotifier
{
    public partial class SpeakerNotifier : UserControl
    {

        #region Properties
        private int _EventID = 1;
        public int EventID
        {
            get { return _EventID; }
            set { _EventID = value; }
        }
        private SomethingSpacialContext domainContext = new SomethingSpacialContext();
        private int LastFeedbackID;
        private static ObservableCollection<EventFeedbackExtended> EventFeedbackCol = new ObservableCollection<EventFeedbackExtended>();
        private int _FeedbacksTimerOffset;
        public int FeedbacksTimerOffset
        {
            get { return _FeedbacksTimerOffset; }
            set { _FeedbacksTimerOffset = value; }
        }
        private int _FeedbacksNotifierTimerOffset;
        public int FeedbacksNotifierTimerOffset
        {
            get { return _FeedbacksNotifierTimerOffset; }
            set { _FeedbacksNotifierTimerOffset = value; }
        }

        //the Timers
        DispatcherTimer myDispatcherTimer;   //This gets in regular periods the Feedbacks from the server.
        DispatcherTimer dtNotifier;          //This shows in regular periods the feedbacks that haven't been shown, shows them one by one and marks them as seen.

	    #endregion

        public SpeakerNotifier()
        {
            InitializeComponent();

            ConfigureSpeakerNotifier();
            InitSpeakerNotifier();
        }

        private void ConfigureSpeakerNotifier()
        {
            this.FeedbacksTimerOffset = 10000;          //  Each 10 seconds we get the feedbacks from the server
            this.FeedbacksNotifierTimerOffset = 6000;   //  each 6 seconds we show off a non-shown Feedback, show it and mark it as shown.
        }


        private void InitSpeakerNotifier()
        {
            //First we get all the Notifications already submitted
            //TODO: Add DateTimeStamp of the moment that the Notification was submitted. will be of help to the speaker.
            //TODO: Good to be able to mark "answered" with a click...
            GetAllEventFeedbacks();

            //After having get all the notifications we get the latest ID and start the timer "background service" for updating
            //the notifications and showing them in a notification and adding htem to the list.
            //We do this when the get operation completes :)
        }

        //JL: Initially we get All the Feedbacks from an Event that's the initial process and assures the app will work in any circunstances, 
        //    and if it does hang, it can be restarted and will be up to date.
        LoadOperation LoadEventFeedbacks ;
        private void GetAllEventFeedbacks() {
            LoadEventFeedbacks = domainContext.Load(domainContext.GetAllEventFeedbacksQuery(EventID));
            LoadEventFeedbacks.Completed += new EventHandler(LoadEventFeedbacks_Completed);
        }
        void LoadEventFeedbacks_Completed(object sender, EventArgs e)
        {
            if (LoadEventFeedbacks.IsComplete == true)
            {
                foreach (Entity entity in LoadEventFeedbacks.Entities)
                {
                    EventFeedback EventFeedback = entity as EventFeedback;
                    EventFeedbackExtended EFE = new EventFeedbackExtended()
                    {
                        Viewed = true,
                        EFB_EventID = EventFeedback.EFB_EventID,
                        EFB_FeedbackContent = EventFeedback.EFB_FeedbackContent,
                        EFB_FeedbackType = EventFeedback.EFB_FeedbackType,
                        EFB_ID = EventFeedback.EFB_ID,
                        EFB_DateTime = EventFeedback.EFB_DateTime,
                        EFB_UserID = EventFeedback.EFB_UserID
                    };

                    EventFeedbackCol.Add(EFE);
                    if (LastFeedbackID < EFE.EFB_ID)
                    {
                        LastFeedbackID = EFE.EFB_ID;
                    }
                }
                SessionFeedbacks.ItemsSource = EventFeedbackCol;

                //After we have got all the latest feedbacks, we launch the notifier process to show the new feedbacks on screen and a process to get 
                // periodically the new feedbacks from the server.
                InitSpeakerNotifierTimer();
                InitFeedbacksNotifier();
            }            

        }


        DispatcherTimer dtTimerToGetFeedBacks;
        int dtTimerToGetFeedBacksSeconds;
        void InitTimerToGetFeedBacks(int seconds) {

            //We start the timer to get feedbacks!
            if (dtTimerToGetFeedBacks == null)
                dtTimerToGetFeedBacks = new DispatcherTimer();

            if (dtTimerToGetFeedBacks.IsEnabled == true)
                dtTimerToGetFeedBacks.Stop();

            dtTimerToGetFeedBacks.Interval = new TimeSpan(0, 0, 1); //Here we count time in seconds :)
            dtTimerToGetFeedBacksSeconds = seconds; //(int)Math.Round((double)(FeedbacksNotifierTimerOffset / 1000), 0);
            dtTimerToGetFeedBacks.Tick += new EventHandler(dtTimerToGetFeedBacks_Tick);
            dtTimerToGetFeedBacks.Start();
        }
        void dtTimerToGetFeedBacks_Tick(object sender, EventArgs e)
        {
            //Updating the counter and the textbox displaying it...
            dtTimerToGetFeedBacksSeconds = dtTimerToGetFeedBacksSeconds - 1;
            this.tbGrabbingFeedsIn.Text = String.Format("{0:00}", dtTimerToGetFeedBacksSeconds.ToString());
            
            //if (
            //     (dtTimerToGetFeedBacksSeconds == 0)
            //     && 
            //     (dtNotifier != null)
            //    )
            //    dtNotifier.Stop();
        }


        #region Notifier code - this is the notifier process that looks for not shown Feedbacks and shows them to the Speaker/user
        private void InitFeedbacksNotifier()
        {
            //Every X the collection is checked for showing the latest FeedbackReceived in a notification window
            dtNotifier = new System.Windows.Threading.DispatcherTimer();
            dtNotifier.Interval = new TimeSpan(0, 0, 0, 0, FeedbacksNotifierTimerOffset); // 100 Milliseconds 
            dtNotifier.Tick += new EventHandler(dtNotifier_Tick);
            dtNotifier.Start();
        }
        private void UpdateFeedbacksNotifier(TimeSpan newInterval)
        {
            //Only updates it if it is "on" ;)
            if (dtNotifier.IsEnabled == true) {
                dtNotifier.Interval = newInterval;
            }
        }
        int LatestFeedBackNotified;
        void dtNotifier_Tick(object sender, EventArgs e)
        {
            foreach (EventFeedbackExtended efe in EventFeedbackCol)
            {
                if ((efe.EFB_ID > LatestFeedBackNotified) &&
                    (efe.Viewed == false))
                {
                    if (App.Current.IsRunningOutOfBrowser)
                    {
                        NotifyFeedback(efe);
                        LatestFeedBackNotified = efe.EFB_ID;
                        efe.Viewed = true;
                    }
                    break;
                }
            }
        }
        private void NotifyFeedback(EventFeedbackExtended efe)
        {
            // create the nofitication window API
            NotificationWindow notify = new NotificationWindow();
            notify.Height = 74;
            notify.Width = 329;

            // creating the content to be in the window
            CustomNotification custom = new CustomNotification();
            custom.Header = efe.EFB_FeedbackType;
            custom.Text = efe.EFB_FeedbackContent;
            custom.Width = notify.Width;
            custom.Height = notify.Height;

            // set the window content
            notify.Content = custom;

            // displaying the notification
            notify.Show(FeedbacksNotifierTimerOffset);
        } 
        #endregion


        private void InitSpeakerNotifierTimer()
        {
            myDispatcherTimer = new System.Windows.Threading.DispatcherTimer();
            myDispatcherTimer.Interval = new TimeSpan(0, 0, 0, 0, FeedbacksTimerOffset); // 100 Milliseconds 
            myDispatcherTimer.Tick += new EventHandler(myDispatcherTimer_Tick);
            myDispatcherTimer.Start();

            int numSeconds = (int)Math.Round((double)(FeedbacksTimerOffset / 1000), 0);
            InitTimerToGetFeedBacks(numSeconds);
        }
        LoadOperation LoadNewEventFeedbacks;
        void myDispatcherTimer_Tick(object sender, EventArgs e)
        {
            //We get the latest feedbacks from the latest FeedbackId & same Event
            LoadNewEventFeedbacks = domainContext.Load(domainContext.GetAllEventFeedbacksFromIdQuery(this.EventID, LastFeedbackID));
            LoadNewEventFeedbacks.Completed += new EventHandler(LoadNewEventFeedbacks_Completed);


            if ((NewFeedbacksTimerOffset != 0) && (NewFeedbacksTimerOffset != FeedbacksTimerOffset)) {
                FeedbacksTimerOffset = NewFeedbacksTimerOffset * 1000;
                myDispatcherTimer.Interval = new TimeSpan(0, 0, 0, 0, FeedbacksTimerOffset); // 100 Milliseconds 
            }

            int numSeconds = (int)Math.Round((double)(FeedbacksTimerOffset / 1000), 0);
            dtTimerToGetFeedBacksSeconds = numSeconds;
        }
        private void UpdateFeedbacksTimerOffset(TimeSpan newInterval)
        {
            //Only updates it if it is "on" ;)
            if (myDispatcherTimer.IsEnabled == true)
            {
                FeedbacksTimerOffset = NewFeedbacksTimerOffset * 1000;
                myDispatcherTimer.Interval = newInterval;
                dtTimerToGetFeedBacksSeconds = NewFeedbacksTimerOffset;


            }
        }

        void LoadNewEventFeedbacks_Completed(object sender, EventArgs e)
        {
            if (LoadNewEventFeedbacks.IsComplete == true)
            {
                foreach (Entity entity in LoadNewEventFeedbacks.Entities)
                {
                    EventFeedback EventFeedback = entity as EventFeedback;

                    EventFeedbackExtended EFE = new EventFeedbackExtended()
                    {
                        Viewed = false,
                        EFB_EventID = EventFeedback.EFB_EventID,
                        EFB_FeedbackContent = EventFeedback.EFB_FeedbackContent,
                        EFB_FeedbackType = EventFeedback.EFB_FeedbackType,
                        EFB_ID = EventFeedback.EFB_ID,
                        EFB_DateTime = EventFeedback.EFB_DateTime,
                        EFB_UserID = EventFeedback.EFB_UserID
                    };

                    EventFeedbackCol.Add(EFE);
                    if (LastFeedbackID < EFE.EFB_ID)
                    {
                        LastFeedbackID = EFE.EFB_ID;
                    }
                }
            }
        }

        //JL: If we change row, whe show the correct feedback content on the textblock at the bottom.
        private void SessionFeedbacks_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            EventFeedbackExtended ef = (EventFeedbackExtended)e.AddedItems[0];
            this.tbFeedback.Text = ef.EFB_FeedbackContent;
        }
        int NewFeedbacksTimerOffset = 0;
        private void slider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
        {
            NewFeedbacksTimerOffset = (int)Math.Round(e.NewValue, 0);
            if ((NewFeedbacksTimerOffset * 1000) < FeedbacksTimerOffset) { 
                //If we have time, we change it right now...
                TimeSpan ts = new TimeSpan(0, 0, 0, NewFeedbacksTimerOffset);
                UpdateFeedbacksTimerOffset(ts); //JL: NOPE it must be set at the next "tick" ;)
            }
            //TimeSpan ts = new TimeSpan(0, 0, 0, newvalue);
            //UpdateFeedbacksTimerOffset(ts); //JL: NOPE it must be set at the next "tick" ;)
        }
    }
}
